home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / mentc.zip / RANDOM.C < prev    next >
C/C++ Source or Header  |  1991-10-16  |  33KB  |  1,214 lines

  1. /*
  2.  * This file contains the command processing functions for a number of random
  3.  * commands. There is no functional grouping here, for sure.
  4.  */
  5.  
  6. #include        <stdio.h>
  7. #include    "estruct.h"
  8. #include    "eproto.h"
  9. #include        "edef.h"
  10. #include    "elang.h"
  11.  
  12. /*
  13.  * Set fill column to n.
  14.  */
  15. PASCAL NEAR setfillcol(f, n)
  16.  
  17. int f,n;    /* prefix flag and argument */
  18.  
  19. {
  20.         fillcol = n;
  21.     mlwrite(TEXT59,n);
  22. /*              "[Fill column is %d]" */
  23.         return(TRUE);
  24. }
  25.  
  26. /*
  27.  * Display the current position of the cursor, in origin 1 X-Y coordinates,
  28.  * the character that is under the cursor (in hex), and the fraction of the
  29.  * text that is before the cursor. The displayed column is not the current
  30.  * column, but the column that would be used on an infinite width display.
  31.  * Normally this is bound to "C-X =".
  32.  */
  33. PASCAL NEAR showcpos(f, n)
  34.  
  35. int f,n;    /* prefix flag and argument */
  36.  
  37. {
  38.         register LINE   *lp;        /* current line */
  39.         register long   numchars;    /* # of chars in file */
  40.         register int    numlines;    /* # of lines in file */
  41.         register long   predchars;    /* # chars preceding point */
  42.         register int    predlines;    /* # lines preceding point */
  43.         register int    curchar;    /* character under cursor */
  44.         int ratio;
  45.         int col;
  46.     int savepos;            /* temp save for current offset */
  47.     int ecol;            /* column pos/end of current line */
  48.  
  49.     /* starting at the beginning of the buffer */
  50.         lp = lforw(curbp->b_linep);
  51.     curchar = '\r';
  52.  
  53.     /* start counting chars and lines */
  54.         numchars = 0;
  55.         numlines = 0;
  56.         while (lp != curbp->b_linep) {
  57.         /* if we are on the current line, record it */
  58.         if (lp == curwp->w_dotp) {
  59.             predlines = numlines;
  60.             predchars = numchars + curwp->w_doto;
  61.             if ((curwp->w_doto) == llength(lp))
  62.                 curchar = '\r';
  63.             else
  64.                 curchar = lgetc(lp, curwp->w_doto);
  65.         }
  66.         /* on to the next line */
  67.         ++numlines;
  68.         numchars += llength(lp) + 1;
  69.         lp = lforw(lp);
  70.         }
  71.  
  72.     /* if at end of file, record it */
  73.     if (curwp->w_dotp == curbp->b_linep) {
  74.         predlines = numlines;
  75.         predchars = numchars;
  76.     }
  77.  
  78.     /* Get real column and end-of-line column. */
  79.     col = getccol(FALSE);
  80.     savepos = curwp->w_doto;
  81.     curwp->w_doto = llength(curwp->w_dotp);
  82.     ecol = getccol(FALSE);
  83.     curwp->w_doto = savepos;
  84.  
  85.         ratio = 0;              /* Ratio before dot. */
  86.         if (numchars != 0)
  87.                 ratio = (100L*predchars) / numchars;
  88.  
  89.     /* summarize and report the info */
  90. #if    DBCS
  91.     if (is2byte(curwp->w_dotp->l_text,
  92.         curwp->w_dotp->l_text + curwp->w_doto)) {
  93.         mlwrite(TEXT220,
  94. /*              "Line %d/%d Col %d/%d Char %D/%D (%d%%) char = 0x%x%x" */
  95.             predlines+1, numlines+1, col, ecol,
  96.             predchars, numchars, ratio, (unsigned char)curchar,
  97.             (unsigned char)(curwp->w_dotp->l_text[curwp->w_doto+1]));
  98.         return(TRUE);
  99.     }
  100. #endif
  101.     mlwrite(TEXT60,
  102. /*              "Line %d/%d Col %d/%d Char %D/%D (%d%%) char = 0x%x" */
  103.         predlines+1, numlines+1, col, ecol,
  104.         predchars, numchars, ratio, curchar);
  105.         return(TRUE);
  106. }
  107.  
  108. PASCAL NEAR getlinenum(bp, sline)    /* get the a line number */
  109.  
  110. BUFFER *bp;    /* buffer to get current line from */
  111. LINE *sline;    /* line to search for */
  112.  
  113. {
  114.         register LINE   *lp;        /* current line */
  115.         register int    numlines;    /* # of lines before point */
  116.  
  117.     /* starting at the beginning of the buffer */
  118.         lp = lforw(bp->b_linep);
  119.  
  120.     /* start counting lines */
  121.         numlines = 0;
  122.         while (lp != bp->b_linep) {
  123.         /* if we are on the current line, record it */
  124.         if (lp == sline)
  125.             break;
  126.         ++numlines;
  127.         lp = lforw(lp);
  128.         }
  129.  
  130.     /* and return the resulting count */
  131.     return(numlines + 1);
  132. }
  133.  
  134. /*
  135.  * Return current column.  Stop at first non-blank given TRUE argument.
  136.  */
  137. PASCAL NEAR getccol(bflg)
  138. int bflg;
  139. {
  140.         register int c, i, col;
  141.         col = 0;
  142.         for (i=0; i<curwp->w_doto; ++i) {
  143.                 c = lgetc(curwp->w_dotp, i);
  144.                 if (c!=' ' && c!='\t' && bflg)
  145.                         break;
  146.                 if (c == '\t')
  147.                         col += -(col % tabsize) + (tabsize - 1);
  148.                 else if (c<0x20 || c==0x7F)
  149.                         ++col;
  150.                 ++col;
  151.         }
  152.         return(col);
  153. }
  154.  
  155. /*
  156.  * Set current column.
  157.  */
  158. PASCAL NEAR setccol(pos)
  159.  
  160. int pos;    /* position to set cursor */
  161.  
  162. {
  163.         register int c;        /* character being scanned */
  164.     register int i;        /* index into current line */
  165.     register int col;    /* current cursor column   */
  166.     register int llen;    /* length of line in bytes */
  167.  
  168.     col = 0;
  169.     llen = llength(curwp->w_dotp);
  170.  
  171.     /* scan the line until we are at or past the target column */
  172.     for (i = 0; i < llen; ++i) {
  173.         /* upon reaching the target, drop out */
  174.         if (col >= pos)
  175.             break;
  176.  
  177.         /* advance one character */
  178.                 c = lgetc(curwp->w_dotp, i);
  179.                 if (c == '\t')
  180.                         col += -(col % tabsize) + (tabsize - 1);
  181.                 else if (c<0x20 || c==0x7F)
  182.                         ++col;
  183.                 ++col;
  184.         }
  185.  
  186.     /* set us at the new position */
  187.     curwp->w_doto = i;
  188.  
  189.     /* and tell weather we made it */
  190.     return(col >= pos);
  191. }
  192.  
  193. /*
  194.  * Twiddle the two characters on either side of dot. If dot is at the end of
  195.  * the line twiddle the two characters before it. Return with an error if dot
  196.  * is at the beginning of line; it seems to be a bit pointless to make this
  197.  * work. This fixes up a very common typo with a single stroke. Normally bound
  198.  * to "C-T". This always works within a line, so "WFEDIT" is good enough.
  199.  */
  200. PASCAL NEAR twiddle(f, n)
  201.  
  202. int f,n;    /* prefix flag and argument */
  203.  
  204. {
  205.         register LINE   *dotp;
  206.         register int    doto;
  207.         register int    cl;
  208.         register int    cr;
  209.  
  210.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  211.         return(rdonly());    /* we are in read only mode    */
  212.         dotp = curwp->w_dotp;
  213.         doto = curwp->w_doto;
  214.         if (doto==llength(dotp) && --doto<0)
  215.                 return(FALSE);
  216.         cr = lgetc(dotp, doto);
  217.         if (--doto < 0)
  218.                 return(FALSE);
  219.         cl = lgetc(dotp, doto);
  220.         lputc(dotp, doto+0, cr);
  221.         lputc(dotp, doto+1, cl);
  222.         lchange(WFEDIT);
  223.         return(TRUE);
  224. }
  225.  
  226. /*
  227.  * Quote the next character, and insert it into the buffer. All the characters
  228.  * are taken literally, including the newline, which does not then have
  229.  * its line splitting meaning. The character is always read, even if it is
  230.  * inserted 0 times, for regularity. Bound to "C-Q"
  231.  */
  232.  
  233. PASCAL NEAR quote(f, n)
  234.  
  235. int f,n;    /* prefix flag and argument */
  236.  
  237. {
  238.         register int c;
  239.  
  240.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  241.         return(rdonly());    /* we are in read only mode    */
  242.         c = tgetc();
  243.         if (n < 0)
  244.                 return(FALSE);
  245.         if (n == 0)
  246.                 return(TRUE);
  247.         return(linsert(n, c));
  248. }
  249.  
  250. /*
  251.  * Set tab size if given non-default argument (n <> 1).  Otherwise, insert a
  252.  * tab into file.  If given argument, n, of zero, change to hard tabs.
  253.  * If n > 1, simulate tab stop every n-characters using spaces. This has to be
  254.  * done in this slightly funny way because the tab (in ASCII) has been turned
  255.  * into "C-I" (in 10 bit code) already. Bound to "C-I".
  256.  */
  257. PASCAL NEAR tab(f, n)
  258.  
  259. int f,n;    /* prefix flag and argument */
  260.  
  261. {
  262.         if (n < 0)
  263.                 return(FALSE);
  264.         if (n == 0 || n > 1) {
  265.                 stabsize = n;
  266.                 return(TRUE);
  267.         }
  268.         if (!stabsize)
  269.                 return(linsert(1, '\t'));
  270.         return(linsert(stabsize - (getccol(FALSE) % stabsize), ' '));
  271. }
  272.  
  273. PASCAL NEAR detab(f, n)    /* change tabs to spaces */
  274.  
  275. int f,n;    /* default flag and numeric repeat count */
  276.  
  277. {
  278.     register int inc;    /* increment to next line [sgn(n)] */
  279.  
  280.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  281.         return(rdonly());    /* we are in read only mode    */
  282.  
  283.     if (f == FALSE)
  284.         n = reglines();
  285.  
  286.     /* loop thru detabbing n lines */
  287.     inc = ((n > 0) ? 1 : -1);
  288.     while (n) {
  289.         curwp->w_doto = 0;    /* start at the beginning */
  290.  
  291.         /* detab the entire current line */
  292.         while (curwp->w_doto < llength(curwp->w_dotp)) {
  293.             /* if we have a tab */
  294.             if (lgetc(curwp->w_dotp, curwp->w_doto) == '\t') {
  295.                 ldelete(1L, FALSE);
  296. /*                insspace(TRUE, 8 - (curwp->w_doto & 7));*/
  297.                 insspace(TRUE, tabsize - (curwp->w_doto % tabsize));
  298.             }
  299.             forwchar(FALSE, 1);
  300.         }
  301.  
  302.         /* advance/or back to the next line */
  303.         forwline(TRUE, inc);
  304.         n -= inc;
  305.     }
  306.     curwp->w_doto = 0;    /* to the begining of the line */
  307.     thisflag &= ~CFCPCN;    /* flag that this resets the goal column */
  308.     lchange(WFEDIT);    /* yes, we have made at least an edit */
  309.     return(TRUE);
  310. }
  311.  
  312.  
  313. PASCAL NEAR entab(f, n)    /* change spaces to tabs where posible */
  314.  
  315. int f,n;    /* default flag and numeric repeat count */
  316.  
  317. {
  318.     register int inc;    /* increment to next line [sgn(n)] */
  319.     register int fspace;    /* pointer to first space if in a run */
  320.     register int ccol;    /* current cursor column */
  321.     register char cchar;    /* current character */
  322.  
  323.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  324.         return(rdonly());    /* we are in read only mode    */
  325.  
  326.     if (f == FALSE)
  327.         n = reglines();
  328.  
  329.     /* loop thru entabbing n lines */
  330.     inc = ((n > 0) ? 1 : -1);
  331.     while (n) {
  332.         /* entab the entire current line */
  333.  
  334.         ccol = curwp->w_doto = 0;    /* start at the beginning */
  335.         fspace = -1;
  336.  
  337.         while (curwp->w_doto < llength(curwp->w_dotp)) {
  338.             /* see if it is time to compress */
  339.             if ((fspace >= 0) && (nextab(fspace) <= ccol))
  340.                 if (ccol - fspace < 2)
  341.                     fspace = -1;
  342.                 else {
  343.                     backchar(TRUE, ccol - fspace);
  344.                     ldelete((long)(ccol - fspace), FALSE);
  345.                     linsert(1, '\t');    
  346.                     fspace = -1;
  347.                 }
  348.  
  349.             /* get the current character */
  350.             cchar = lgetc(curwp->w_dotp, curwp->w_doto);
  351.  
  352.             switch (cchar) {
  353.                 case '\t': /* a tab...count em up (no break here)  */
  354.                     ldelete(1L, FALSE);
  355.                     insspace(TRUE, tabsize - (ccol % tabsize));
  356.  
  357.                 case ' ':  /* a space...compress? */
  358.                     if (fspace == -1)
  359.                         fspace = ccol;
  360.                     break;
  361.  
  362.                 default:   /* any other char...just count */
  363.                     fspace = -1;
  364.                     break;
  365.             }
  366.             ccol++;
  367.             forwchar(FALSE, 1);
  368.         }
  369.  
  370.         /* advance/or back to the next line */
  371.         forwline(TRUE, inc);
  372.         n -= inc;
  373.         curwp->w_doto = 0;    /* start at the beginning */
  374.     }
  375.     curwp->w_doto = 0;    /* to the begining of the line */
  376.     thisflag &= ~CFCPCN;    /* flag that this resets the goal column */
  377.     lchange(WFEDIT);    /* yes, we have made at least an edit */
  378.     return(TRUE);
  379. }
  380.  
  381. /* trim:    trim trailing whitespace from the point to eol
  382.         with no arguments, it trims the current region
  383. */
  384.  
  385. PASCAL NEAR trim(f, n)
  386.  
  387. int f,n;    /* default flag and numeric repeat count */
  388.  
  389. {
  390.     register LINE *lp;    /* current line pointer */
  391.     register int offset;    /* original line offset position */
  392.     register int length;    /* current length */
  393.     register int inc;    /* increment to next line [sgn(n)] */
  394.  
  395.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  396.         return(rdonly());    /* we are in read only mode    */
  397.  
  398.     if (f == FALSE)
  399.         n = reglines();
  400.  
  401.     /* loop thru trimming n lines */
  402.     inc = ((n > 0) ? 1 : -1);
  403.     while (n) {
  404.         lp = curwp->w_dotp;        /* find current line text */
  405.         offset = curwp->w_doto;        /* save original offset */
  406.         length = lp->l_used;        /* find current length */
  407.  
  408.         /* trim the current line */
  409.         while (length > offset) {
  410.             if (lgetc(lp, length-1) != ' ' &&
  411.                 lgetc(lp, length-1) != '\t')
  412.                     break;
  413.             length--;
  414.         }
  415.         lp->l_used = length;
  416.  
  417.         /* advance/or back to the next line */
  418.         forwline(TRUE, inc);
  419.         n -= inc;
  420.     }
  421.     lchange(WFEDIT);
  422.     thisflag &= ~CFCPCN;    /* flag that this resets the goal column */
  423.     return(TRUE);
  424. }
  425.  
  426. /*
  427.  * Open up some blank space. The basic plan is to insert a bunch of newlines,
  428.  * and then back up over them. Everything is done by the subcommand
  429.  * procerssors. They even handle the looping. Normally this is bound to "C-O".
  430.  */
  431. PASCAL NEAR openline(f, n)
  432.  
  433. int f,n;    /* prefix flag and argument */
  434.  
  435. {
  436.         register int    i;
  437.         register int    s;
  438.  
  439.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  440.         return(rdonly());    /* we are in read only mode    */
  441.         if (n < 0)
  442.                 return(FALSE);
  443.         if (n == 0)
  444.                 return(TRUE);
  445.         i = n;                                  /* Insert newlines.     */
  446.         do {
  447.                 s = lnewline();
  448.         } while (s==TRUE && --i);
  449.         if (s == TRUE)                          /* Then back up overtop */
  450.                 s = backchar(f, n);             /* of them all.         */
  451.         return(s);
  452. }
  453.  
  454. /*
  455.  * Insert a newline. Bound to "C-M". If we are in CMODE, do automatic
  456.  * indentation as specified.
  457.  */
  458. PASCAL NEAR newline(f, n)
  459.  
  460. int f,n;    /* prefix flag and argument */
  461.  
  462. {
  463.     register int    s;
  464.  
  465.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  466.         return(rdonly());    /* we are in read only mode    */
  467.     if (n < 0)
  468.         return(FALSE);
  469.  
  470.     /* if we are in C mode and this is a default <NL> */
  471.     if (n == 1 && (curbp->b_mode & MDCMOD) &&
  472.         curwp->w_dotp != curbp->b_linep)
  473.         return(cinsert());
  474.  
  475.         /*
  476.          * If a newline was typed, fill column is defined, the argument is non-
  477.          * negative, wrap mode is enabled, and we are now past fill column,
  478.      * and we are not read-only, perform word wrap.
  479.          */
  480.         if ((curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 &&
  481.         getccol(FALSE) > fillcol &&
  482.         (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
  483.         execkey(&wraphook, FALSE, 1);
  484.  
  485.     /* insert some lines */
  486.     while (n--) {
  487.         if ((s=lnewline()) != TRUE)
  488.             return(s);
  489.     }
  490.     return(TRUE);
  491. }
  492.  
  493. PASCAL NEAR cinsert()    /* insert a newline and indentation for C */
  494.  
  495. {
  496.     register char *cptr;    /* string pointer into text to copy */
  497.     register int i;        /* index into line to copy indent from */
  498.     register int llen;    /* length of line to copy indent from */
  499.     register int bracef;    /* was there a brace at the end of line? */
  500.     register LINE *lp;    /* current line pointer */
  501.     register int offset;
  502.     char ichar[NSTRING];    /* buffer to hold indent of last line */
  503.  
  504.     /* trim the whitespace before the point */
  505.     lp = curwp->w_dotp;
  506.     offset = curwp->w_doto;
  507.     while (offset > 0 &&
  508.         (lgetc(lp, offset - 1) == ' ' ||
  509.         lgetc(lp, offset - 1) == '\t')) {
  510.         backdel(FALSE, 1);
  511.                offset--;
  512.     }
  513.  
  514.     /* check for a brace */
  515.     bracef = (offset > 0 && lgetc(lp, offset - 1) == '{');
  516.  
  517.     /* put in the newline */
  518.     if (lnewline() == FALSE)
  519.         return(FALSE);
  520.  
  521.     /* if the new line is not blank... don't indent it! */
  522.     lp = curwp->w_dotp;
  523.     if (lp->l_used != 0)
  524.         return(TRUE);
  525.  
  526.     /* hunt for the last non-blank line to get indentation from */
  527.     while (lp->l_used == 0 && lp != curbp->b_linep)
  528.         lp = lp->l_bp;
  529.  
  530.     /* grab a pointer to text to copy indentation from */
  531.     cptr = &(lp->l_text[0]);
  532.     llen = lp->l_used;
  533.  
  534.     /* save the indent of the last non blank line */
  535.     i = 0;
  536.     while ((i < llen) && (cptr[i] == ' ' || cptr[i] == '\t')
  537.         && (i < NSTRING - 1)) {
  538.         ichar[i] = cptr[i];
  539.         ++i;
  540.     }
  541.     ichar[i] = 0;        /* terminate it */
  542.  
  543.     /* insert this saved indentation */
  544.     linstr(ichar);
  545.  
  546.     /* and one more tab for a brace */
  547.     if (bracef)
  548.         tab(FALSE, 1);
  549.  
  550.     return(TRUE);
  551. }
  552.  
  553. PASCAL NEAR insbrace(n, c)    /* insert a brace into the text here...we are in CMODE */
  554.  
  555. int n;    /* repeat count */
  556. int c;    /* brace to insert (always } for now) */
  557.  
  558. {
  559.     register int ch;    /* last character before input */
  560.     register int oc;    /* caractere oppose a c */
  561.     register int i, count;
  562.     register int target;    /* column brace should go after */
  563.     register LINE *oldlp;
  564.     register int  oldoff;
  565.  
  566.     /* if we aren't at the beginning of the line... */
  567.     if (curwp->w_doto != 0)
  568.  
  569.     /* scan to see if all space before this is white space */
  570.         for (i = curwp->w_doto - 1; i >= 0; --i) {
  571.             ch = lgetc(curwp->w_dotp, i);
  572.             if (ch != ' ' && ch != '\t')
  573.                 return(linsert(n, c));
  574.         }
  575.  
  576.     /* chercher le caractere oppose correspondant */
  577.     switch (c) {
  578.         case '}': oc = '{'; break;
  579.         case ']': oc = '['; break;
  580.         case ')': oc = '('; break;
  581.         default: return(FALSE);
  582.     }
  583.     
  584.     oldlp = curwp->w_dotp;
  585.     oldoff = curwp->w_doto;
  586.     
  587.     count = 1; backchar(FALSE, 1);
  588.     
  589.     while (count > 0) {
  590.         if (curwp->w_doto == llength(curwp->w_dotp))
  591.             ch = '\r';
  592.         else
  593.             ch = lgetc(curwp->w_dotp, curwp->w_doto);
  594.  
  595.         if (ch == c)  ++count;
  596.         if (ch == oc) --count;
  597.         
  598.         backchar(FALSE, 1);
  599.         if (boundry(curwp->w_dotp, curwp->w_doto, REVERSE))
  600.             break;
  601.     }
  602.     
  603.     if (count != 0) {    /* no match */
  604.         curwp->w_dotp = oldlp;
  605.         curwp->w_doto = oldoff;
  606.         return(linsert(n, c));
  607.     }
  608.     
  609.     curwp->w_doto = 0;        /* debut de ligne */
  610.     /* aller au debut de la ligne apres la tabulation */
  611.     while ((ch = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || ch == '\t')
  612.         forwchar(FALSE, 1);
  613.  
  614.     /* delete back first */
  615.     target = getccol(FALSE);    /* c'est l'indent que l'on doit avoir */
  616.     curwp->w_dotp = oldlp;
  617.     curwp->w_doto = oldoff;
  618.     
  619.     while (target != getccol(FALSE)) {
  620.         if (target < getccol(FALSE))    /* on doit detruire des caracteres */
  621.             while (getccol(FALSE) > target)
  622.                 backdel(FALSE, 1);
  623.         else {                /* on doit en inserer */
  624.             while (target - getccol(FALSE) >= tabsize)
  625.                 linsert(1,'\t');
  626.             linsert(target - getccol(FALSE), ' ');
  627.         }
  628.     }
  629.  
  630.     /* and insert the required brace(s) */
  631.     return(linsert(n, c));
  632. }
  633.  
  634. PASCAL NEAR inspound()    /* insert a # into the text here...we are in CMODE */
  635.  
  636. {
  637.     register int ch;    /* last character before input */
  638.     register int i;
  639.  
  640.     /* if we are at the beginning of the line, no go */
  641.     if (curwp->w_doto == 0)
  642.         return(linsert(1,'#'));
  643.  
  644.     /* scan to see if all space before this is white space */
  645.     for (i = curwp->w_doto - 1; i >= 0; --i) {
  646.         ch = lgetc(curwp->w_dotp, i);
  647.         if (ch != ' ' && ch != '\t')
  648.             return(linsert(1, '#'));
  649.     }
  650.  
  651.     /* delete back first */
  652.     while (getccol(FALSE) >= 1)
  653.         backdel(FALSE, 1);
  654.  
  655.     /* and insert the required pound */
  656.     return(linsert(1, '#'));
  657. }
  658.  
  659. /*
  660.  * Delete blank lines around dot. What this command does depends if dot is
  661.  * sitting on a blank line. If dot is sitting on a blank line, this command
  662.  * deletes all the blank lines above and below the current line. If it is
  663.  * sitting on a non blank line then it deletes all of the blank lines after
  664.  * the line. Normally this command is bound to "C-X C-O". Any argument is
  665.  * ignored.
  666.  */
  667. PASCAL NEAR deblank(f, n)
  668.  
  669. int f,n;    /* prefix flag and argument */
  670.  
  671. {
  672.         register LINE   *lp1;
  673.         register LINE   *lp2;
  674.         long nld;
  675.  
  676.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  677.         return(rdonly());    /* we are in read only mode    */
  678.         lp1 = curwp->w_dotp;
  679.         while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep)
  680.                 lp1 = lp2;
  681.         lp2 = lp1;
  682.         nld = 0;
  683.         while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0)
  684.                 ++nld;
  685.         if (nld == 0)
  686.                 return(TRUE);
  687.         curwp->w_dotp = lforw(lp1);
  688.         curwp->w_doto = 0;
  689.         return(ldelete(nld, FALSE));
  690. }
  691.  
  692. /*
  693.  * Insert a newline, then enough tabs and spaces to duplicate the indentation
  694.  * of the previous line. Tabs are every tabsize characters. Quite simple.
  695.  * Figure out the indentation of the current line. Insert a newline by calling
  696.  * the standard routine. Insert the indentation by inserting the right number
  697.  * of tabs and spaces. Return TRUE if all ok. Return FALSE if one of the
  698.  * subcomands failed. Normally bound to "C-J".
  699.  */
  700. PASCAL NEAR indent(f, n)
  701.  
  702. int f,n;    /* prefix flag and argument */
  703.  
  704. {
  705.         register int    nicol;
  706.         register int    c;
  707.         register int    i;
  708.  
  709.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  710.         return(rdonly());    /* we are in read only mode    */
  711.         if (n < 0)
  712.                 return(FALSE);
  713.         while (n--) {
  714.                 nicol = 0;
  715.                 for (i=0; i<llength(curwp->w_dotp); ++i) {
  716.                         c = lgetc(curwp->w_dotp, i);
  717.                         if (c!=' ' && c!='\t')
  718.                                 break;
  719.                         if (c == '\t')
  720.                 nicol += -(nicol % tabsize) + (tabsize - 1);
  721.                         ++nicol;
  722.                 }
  723.                 if (lnewline() == FALSE
  724.                 || ((i=nicol/tabsize)!=0 && linsert(i, '\t')==FALSE)
  725.                 || ((i=nicol%tabsize)!=0 && linsert(i,  ' ')==FALSE))
  726.                         return(FALSE);
  727.         }
  728.         return(TRUE);
  729. }
  730.  
  731. /*
  732.  * Delete forward. This is real easy, because the basic delete routine does
  733.  * all of the work. Watches for negative arguments, and does the right thing.
  734.  * If any argument is present, it kills rather than deletes, to prevent loss
  735.  * of text if typed with a big argument. Normally bound to "C-D".
  736.  */
  737. PASCAL NEAR forwdel(f, n)
  738.  
  739. int f,n;    /* prefix flag and argument */
  740.  
  741. {
  742.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  743.         return(rdonly());    /* we are in read only mode    */
  744.         if (n < 0)
  745.                 return(backdel(f, -n));
  746.         if (f != FALSE) {                       /* Really a kill.       */
  747.                 if ((lastflag&CFKILL) == 0)
  748.                         kdelete();
  749.                 thisflag |= CFKILL;
  750.         }
  751.         return(ldelete((long)n, f));
  752. }
  753.  
  754. /*
  755.  * Delete backwards. This is quite easy too, because it's all done with other
  756.  * functions. Just move the cursor back, and delete forwards. Like delete
  757.  * forward, this actually does a kill if presented with an argument. Bound to
  758.  * both "RUBOUT" and "C-H".
  759.  */
  760. PASCAL NEAR backdel(f, n)
  761.  
  762. int f,n;    /* prefix flag and argument */
  763.  
  764. {
  765.         register int    s;
  766.  
  767.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  768.         return(rdonly());    /* we are in read only mode    */
  769.         if (n < 0)
  770.                 return(forwdel(f, -n));
  771.         if (f != FALSE) {                       /* Really a kill.       */
  772.                 if ((lastflag&CFKILL) == 0)
  773.                         kdelete();
  774.                 thisflag |= CFKILL;
  775.         }
  776.         if ((s=backchar(f, n)) == TRUE)
  777.                 s = ldelete((long)n, f);
  778.         return(s);
  779. }
  780.  
  781. /*
  782.  * Kill text. If called without an argument, it kills from dot to the end of
  783.  * the line, unless it is at the end of the line, when it kills the newline.
  784.  * If called with an argument of 0, it kills from the start of the line to dot.
  785.  * If called with a positive argument, it kills from dot forward over that
  786.  * number of newlines. If called with a negative argument it kills backwards
  787.  * that number of newlines. Normally bound to "C-K".
  788.  */
  789. PASCAL NEAR killtext(f, n)
  790.  
  791. int f,n;    /* prefix flag and argument */
  792.  
  793. {
  794.         register LINE   *nextp;
  795.         long chunk;
  796.  
  797.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  798.         return(rdonly());    /* we are in read only mode    */
  799.         if ((lastflag&CFKILL) == 0)             /* Clear kill buffer if */
  800.                 kdelete();                      /* last wasn't a kill.  */
  801.         thisflag |= CFKILL;
  802.  
  803.         if (f == FALSE) {
  804.                 chunk = llength(curwp->w_dotp)-curwp->w_doto;
  805.                 if (chunk == 0)
  806.                         chunk = 1;
  807.     } else if (n == 0) {
  808.                 chunk = -curwp->w_doto;
  809.         } else if (n > 0) {
  810.                 chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
  811.                 nextp = lforw(curwp->w_dotp);
  812.                 while (--n) {
  813.                         if (nextp == curbp->b_linep)
  814.                                 return(FALSE);
  815.                         chunk += llength(nextp)+1;
  816.                         nextp = lforw(nextp);
  817.                 }
  818.         } else if (n < 0) {
  819.                 chunk = -curwp->w_doto;
  820.                 nextp = lback(curwp->w_dotp);
  821.                 while (n++) {
  822.                         if (nextp == curbp->b_linep)
  823.                                 return(FALSE);
  824.                         chunk -= llength(nextp)+1;
  825.                         nextp = lback(nextp);
  826.                 }
  827.         }
  828.         return(ldelete(chunk, TRUE));
  829. }
  830.  
  831. PASCAL NEAR setmod(f, n)    /* prompt and set an editor mode */
  832.  
  833. int f, n;    /* default and argument */
  834.  
  835. {
  836.     return(adjustmode(TRUE, FALSE));
  837. }
  838.  
  839. PASCAL NEAR delmode(f, n)    /* prompt and delete an editor mode */
  840.  
  841. int f, n;    /* default and argument */
  842.  
  843. {
  844.     return(adjustmode(FALSE, FALSE));
  845. }
  846.  
  847. PASCAL NEAR setgmode(f, n)    /* prompt and set a global editor mode */
  848.  
  849. int f, n;    /* default and argument */
  850.  
  851. {
  852.     return(adjustmode(TRUE, TRUE));
  853. }
  854.  
  855. PASCAL NEAR delgmode(f, n)    /* prompt and delete a global editor mode */
  856.  
  857. int f, n;    /* default and argument */
  858.  
  859. {
  860.     return(adjustmode(FALSE, TRUE));
  861. }
  862.  
  863. PASCAL NEAR adjustmode(kind, global)    /* change the editor mode status */
  864.  
  865. int kind;    /* true = set,        false = delete */
  866. int global;    /* true = global flag,    false = current buffer flag */
  867. {
  868.     register char *scan;        /* scanning pointer to convert prompt */
  869.     register int i;            /* loop index */
  870.     register int status;        /* error return on input */
  871. #if    COLOR
  872.     register int uflag;        /* was modename uppercase?    */
  873. #endif
  874.     char prompt[50];    /* string to prompt user with */
  875.     char cbuf[NPAT];        /* buffer to recieve mode name into */
  876.  
  877.     /* build the proper prompt string */
  878.     if (global)
  879.         strcpy(prompt,TEXT62);
  880. /*                            "Global mode to " */
  881.     else
  882.         strcpy(prompt,TEXT63);
  883. /*                            "Mode to " */
  884.  
  885.     if (kind == TRUE)
  886.         strcat(prompt, TEXT64);
  887. /*                             "add: " */
  888.     else
  889.         strcat(prompt, TEXT65);
  890. /*                             "delete: " */
  891.  
  892.     /* prompt the user and get an answer */
  893.  
  894.     status = mlreply(prompt, cbuf, NPAT - 1);
  895.     if (status != TRUE)
  896.         return(status);
  897.  
  898.     /* make it uppercase */
  899.  
  900.     scan = cbuf;
  901. #if    COLOR
  902.     uflag = (*scan >= 'A' && *scan <= 'Z');
  903. #endif
  904.     while (*scan)
  905.         uppercase(scan++);
  906.  
  907.     /* test it first against the colors we know */
  908.     if ((i = lookup_color(cbuf)) != -1) {
  909.  
  910. #if    COLOR
  911.         /* finding the match, we set the color */
  912.         if (global) {
  913.             if (uflag)
  914.                 gfcolor = i;
  915.             else
  916.                 gbcolor = i;
  917. #if    WINDOW_TEXT & 0
  918.             refresh_screen(first_screen);
  919. #endif
  920.         } else
  921.             if (uflag)
  922.                 curwp->w_fcolor = i;
  923.             else
  924.                 curwp->w_bcolor = i;
  925.  
  926.         curwp->w_flag |= WFCOLR;
  927. #endif
  928.         mlerase();
  929.         return(TRUE);
  930.     }
  931.  
  932.     /* test it against the modes we know */
  933.  
  934.     for (i=0; i < NUMMODES; i++) {
  935.         if (strcmp(cbuf, modename[i]) == 0) {
  936.             /* finding a match, we process it */
  937.             if (kind == TRUE)
  938.                 if (global) {
  939.                     gmode |= (1 << i);
  940.                     if ((1 << i) == MDOVER)
  941.                         gmode &= ~MDREPL;
  942.                     else if ((1 << i) == MDREPL)
  943.                         gmode &= ~MDOVER;
  944.                 } else {
  945.                     curbp->b_mode |= (1 << i);
  946.                     if ((1 << i) == MDOVER)
  947.                         curbp->b_mode &= ~MDREPL;
  948.                     else if ((1 << i) == MDREPL)
  949.                         curbp->b_mode &= ~MDOVER;
  950.                 }
  951.             else
  952.                 if (global)
  953.                     gmode &= ~(1 << i);
  954.                 else
  955.                     curbp->b_mode &= ~(1 << i);
  956.             /* display new mode line */
  957.             if (global == 0)
  958.                 upmode();
  959.             mlerase();    /* erase the junk */
  960.             return(TRUE);
  961.         }
  962.     }
  963.  
  964.     mlwrite(TEXT66);
  965. /*              "No such mode!" */
  966.     return(FALSE);
  967. }
  968.  
  969. /*    This function simply clears the message line,
  970.         mainly for macro usage            */
  971.  
  972. PASCAL NEAR clrmes(f, n)
  973.  
  974. int f, n;    /* arguments ignored */
  975.  
  976. {
  977.     mlforce("");
  978.     return(TRUE);
  979. }
  980.  
  981. /*    This function writes a string on the message line
  982.         mainly for macro usage            */
  983.  
  984. PASCAL NEAR writemsg(f, n)
  985.  
  986. int f, n;    /* arguments ignored */
  987.  
  988. {
  989.     register int status;
  990.     char buf[NPAT];        /* buffer to recieve message into */
  991.  
  992.     if ((status = mlreply(TEXT67, buf, NPAT - 1)) != TRUE)
  993. /*                            "Message to write: " */
  994.         return(status);
  995.  
  996.     /* expand all '%' to "%%" so mlwrite won't expect arguments */
  997.     makelit(buf);
  998.  
  999.     /* write the message out */
  1000.     mlforce(buf);
  1001.     return(TRUE);
  1002. }
  1003.  
  1004. /*    the cursor is moved to a matching fence    */
  1005.  
  1006. PASCAL NEAR getfence(f, n)
  1007.  
  1008. int f, n;    /* not used */
  1009.  
  1010. {
  1011.     register LINE *oldlp;    /* original line pointer */
  1012.     register int oldoff;    /* and offset */
  1013.     register int sdir;    /* direction of search (1/-1) */
  1014.     register int count;    /* current fence level count */
  1015.     register char ch;    /* fence type to match against */
  1016.     register char ofence;    /* open fence */
  1017.     register char c;    /* current character in scan */
  1018.  
  1019.     /* save the original cursor position */
  1020.     oldlp = curwp->w_dotp;
  1021.     oldoff = curwp->w_doto;
  1022.  
  1023.     /* get the current character */
  1024.     if (oldoff == llength(oldlp))
  1025.         ch = '\r';
  1026.     else
  1027.         ch = lgetc(oldlp, oldoff);
  1028.  
  1029.     /* setup proper matching fence */
  1030.     switch (ch) {
  1031.         case '(': ofence = ')'; sdir = FORWARD; break;
  1032.         case '{': ofence = '}'; sdir = FORWARD; break;
  1033.         case '[': ofence = ']'; sdir = FORWARD; break;
  1034.         case ')': ofence = '('; sdir = REVERSE; break;
  1035.         case '}': ofence = '{'; sdir = REVERSE; break;
  1036.         case ']': ofence = '['; sdir = REVERSE; break;
  1037.         default: TTbeep(); return(FALSE);
  1038.     }
  1039.  
  1040.     /* set up for scan */
  1041.     count = 1;
  1042.  
  1043.     /* scan until we find it, or reach the end of file */
  1044.     while (count > 0) {
  1045.         if (sdir == FORWARD)
  1046.             forwchar(FALSE, 1);
  1047.         else
  1048.             backchar(FALSE, 1);
  1049.  
  1050.         if (curwp->w_doto == llength(curwp->w_dotp))
  1051.             c = '\r';
  1052.         else
  1053.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  1054.         if (c == ch)
  1055.             ++count;
  1056.         if (c == ofence)
  1057.             --count;
  1058.         if (boundry(curwp->w_dotp, curwp->w_doto, sdir))
  1059.             break;
  1060.     }
  1061.  
  1062.     /* if count is zero, we have a match, move the sucker */
  1063.     if (count == 0) {
  1064.         curwp->w_flag |= WFMOVE;
  1065.         return(TRUE);
  1066.     }
  1067.  
  1068.     /* restore the current position */
  1069.     curwp->w_dotp = oldlp;
  1070.     curwp->w_doto = oldoff;
  1071.     TTbeep();
  1072.     return(FALSE);
  1073. }
  1074.  
  1075. /*    Close fences are matched against their partners, and if
  1076.     on screen the cursor briefly lights there        */
  1077.  
  1078. #if    PROTO
  1079. PASCAL NEAR fmatch(char ch)
  1080. #else
  1081. PASCAL NEAR fmatch(ch)
  1082.  
  1083. char ch;    /* fence type to match against */
  1084. #endif
  1085.  
  1086. {
  1087.     register LINE *oldlp;    /* original line pointer */
  1088.     register int oldoff;    /* and offset */
  1089.     register LINE *toplp;    /* top line in current window */
  1090.     register int count;    /* current fence level count */
  1091.     register char opench;    /* open fence */
  1092.     register char c;    /* current character in scan */
  1093.     register int i;
  1094.  
  1095.     /* first get the display update out there */
  1096.     update(FALSE);
  1097.  
  1098.     /* save the original cursor position */
  1099.     oldlp = curwp->w_dotp;
  1100.     oldoff = curwp->w_doto;
  1101.  
  1102.     /* setup proper open fence for passed close fence */
  1103.     if (ch == ')')
  1104.         opench = '(';
  1105.     else if (ch == '}')
  1106.         opench = '{';
  1107.     else
  1108.         opench = '[';
  1109.  
  1110.     /* find the top line and set up for scan */
  1111.     toplp = curwp->w_linep->l_bp;
  1112.     count = 1;
  1113.     backchar(FALSE, 1);
  1114.  
  1115.     /* scan back until we find it, or reach past the top of the window */
  1116.     while (count > 0 && curwp->w_dotp != toplp) {
  1117.         backchar(FALSE, 1);
  1118.         if (curwp->w_doto == llength(curwp->w_dotp))
  1119.             c = '\r';
  1120.         else
  1121.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  1122.         if (c == ch)
  1123.             ++count;
  1124.         if (c == opench)
  1125.             --count;
  1126.         if (curwp->w_dotp == curwp->w_bufp->b_linep->l_fp &&
  1127.             curwp->w_doto == 0)
  1128.             break;
  1129.     }
  1130.  
  1131.     /* if count is zero, we have a match, display the sucker */
  1132.     /* there is a real machine dependant timing problem here we have
  1133.        yet to solve......... */
  1134.     if (count == 0) {
  1135.         for (i = 0; i < term.t_pause; i++)
  1136.             update(FALSE);
  1137.     }
  1138.  
  1139.     /* restore the current position */
  1140.     curwp->w_dotp = oldlp;
  1141.     curwp->w_doto = oldoff;
  1142.     return(TRUE);
  1143. }
  1144.  
  1145. PASCAL NEAR istring(f, n)    /* ask for and insert a string into the current
  1146.            buffer at the current point */
  1147.  
  1148. int f, n;    /* ignored arguments */
  1149.  
  1150. {
  1151.     register int status;    /* status return code */
  1152.     char tstring[NPAT+1];    /* string to add */
  1153.  
  1154.     /* ask for string to insert */
  1155.     status = mltreply(TEXT68, tstring, NPAT, sterm);
  1156. /*                        "String to insert<META>: " */
  1157.     if (status != TRUE)
  1158.         return(status);
  1159.  
  1160.     if (f == FALSE)
  1161.         n = 1;
  1162.  
  1163.     if (n < 0)
  1164.         n = - n;
  1165.  
  1166.     /* insert it */
  1167.     while (n-- && (status = linstr(tstring)))
  1168.         ;
  1169.     return(status);
  1170. }
  1171.  
  1172. PASCAL NEAR ovstring(f, n) /* ask for and overwite a string into the current
  1173.            buffer at the current point */
  1174.  
  1175. int f, n;    /* ignored arguments */
  1176.  
  1177. {
  1178.     register int status;    /* status return code */
  1179.     char tstring[NPAT+1];    /* string to add */
  1180.  
  1181.     /* ask for string to insert */
  1182.     status = mltreply(TEXT69, tstring, NPAT, sterm);
  1183. /*                        "String to overwrite<META>: " */
  1184.     if (status != TRUE)
  1185.         return(status);
  1186.  
  1187.     if (f == FALSE)
  1188.         n = 1;
  1189.  
  1190.     if (n < 0)
  1191.         n = - n;
  1192.  
  1193.     /* insert it */
  1194.     while (n-- && (status = lover(tstring)))
  1195.         ;
  1196.     return(status);
  1197. }
  1198.  
  1199. int PASCAL NEAR lookup_color(sp)
  1200.  
  1201. char *sp;    /* name to look up */
  1202.  
  1203. {
  1204.     register int i;        /* index into color list */
  1205.  
  1206.     /* test it against the colors we know */
  1207.     for (i = 0; i < NCOLORS; i++) {
  1208.         if (strcmp(sp, cname[i]) == 0)
  1209.             return(i);
  1210.     }
  1211.     return(-1);
  1212. }
  1213.  
  1214.